package jmine.tec.services.export.impl;

import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;

import jmine.tec.services.api.export.ReferenceMap;

/**
 * Implementação default da interface ReferenceMap.
 * 
 * @author lundberg
 */
public class ReferenceMapImpl implements ReferenceMap {

    private Map<Object, String> referenceMap = new IdentityHashMap<Object, String>();

    private Set<String> generatedReferences = new HashSet<String>();

    /**
     * {@inheritDoc}
     */
    public String addReference(Object entity, String referencePrefix) {
        Object narrowed = ExportUtils.narrow(entity);
        if (this.containsReference(narrowed)) {
            return this.getReference(narrowed);
        } else {
            String reference = this.createReference(referencePrefix);
            this.referenceMap.put(narrowed, reference);
            return reference;
        }
    }

    /**
     * {@inheritDoc}
     */
    public boolean containsReference(Object entity) {
        Object narrowed = ExportUtils.narrow(entity);
        return this.referenceMap.containsKey(narrowed);
    }

    /**
     * {@inheritDoc}
     */
    public String getReference(Object entity) {
        Object narrowed = ExportUtils.narrow(entity);
        return this.referenceMap.get(narrowed);
    }

    /**
     * Cria um novo nome de referencia, que não exista no mapa.
     * 
     * @param referencePrefix referencePrefix
     * @return referencia.
     */
    private String createReference(String referencePrefix) {
        int i = 0;
        while (this.generatedReferences.contains(this.createReference(referencePrefix, i))) {
            i++;
        }
        String reference = this.createReference(referencePrefix, i);
        this.generatedReferences.add(reference);
        return reference;
    }

    /**
     * Cria uma referencia dado o índice.
     * 
     * @param referencePrefix referencePrefix
     * @param idx índice.
     * @return string
     */
    private String createReference(String referencePrefix, int idx) {
        return "$" + referencePrefix + Integer.toString(idx);
    }
}
